using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Collections.Specialized;
using System.Collections.Generic;
using Updater;
using TheLogWatcher.Properties;

namespace TheLogWatcher
{
    public partial class MainWindow : Form
    {
        public MainWindow(string[] args)
        {
            InitializeComponent();
            if (args != null && args.Length > 0)
            {
                bool success = LoadLogfile(args[0]);
                if (!success)
                {
                    MessageBox.Show("Cannot open logfile !", "Loading Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                }
            }
        }

        private void benchmark()
        {
            //System.Diagnostics.Process proc = new System.Diagnostics.Process();
            //proc.PagedMemorySize64;
            //proc.PagedSystemMemorySize64;
            //proc.PrivilegedProcessorTime;
            //proc.TotalProcessorTime;
            //proc.UserProcessorTime;
            //proc.VirtualMemorySize64;

            System.Diagnostics.PerformanceCounter myCounter;
            myCounter = new System.Diagnostics.PerformanceCounter();

            myCounter.CategoryName = "Processor";
            myCounter.CounterName = "% Processor Time";
            myCounter.InstanceName = "_Total";

            for (int i = 0; i < 20; i++)
                myCounter.NextValue();

        }

        private static Settings sets = Settings.Default;

        /// <summary>
        ///     This one stores all or data for several message types.
        /// </summary>
        private Dictionary<MessageTypes, List<LogEntry>> data;

        private DataAccess dataAccess;

        private ColumnManager colMan;

        private List<LogEntry> getData(string type)
        {
            if (type != null && this.data != null)
            {
                MessageTypes msgType = MessageType.GetMessageType(type);
                if (this.data.ContainsKey(msgType))
                {
                    return this.data[msgType];
                }
            }
            return null;
        }

        private List<LogEntry> getData(int typeIndex)
        {
            if (this.data != null)
            {
                MessageTypes msgType = MessageType.MessageTypeAt(typeIndex);
                if (this.data.ContainsKey(msgType))
                {
                    return this.data[msgType];
                }
            }
            return null;
        }

        // Currently this is not supported because values are always overwritten
        private void OpenSeveralLogfiles(string[] loadThis)
        {
            for (int i = 0; i < loadThis.Length; i++)
            {
                //OpenLogfile(loadThis[i]);
            }
        }

        /// <summary>
        ///     Calculates the dividor that's needed for progress bar to bar
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public double getProgressBarDividor(FileStream str)
        {
            //  Calculate maximum and divider for progress bar
            double dividor = 0;
            Int32 max = 0;
            long value = str.Length;
            if (value > Int32.MaxValue)
            {
                dividor = (double)value / Int32.MaxValue;
                max = Int32.MaxValue;
            }
            else
            {
                max = (int)value;
            }
            loadFileProgressBar.Maximum = max;
            return dividor;
        }

        /// <summary>
        ///     Increments progress bar to the specified value.
        /// </summary>
        /// <param name="dividor"></param>
        /// <param name="position"></param>
        public void incrementProgressBar(double dividor, long position)
        {
            // update progress bar
            int realnumber = (int)position;
            if (dividor != 0)
            {
                // Number is bigger than integer
                realnumber = (int)(position / dividor);
            }
            loadFileProgressBar.Value = realnumber;
        }

        private void cleanSingleType(MessageTypes type)
        {
            if (this.data != null && this.data.ContainsKey(type))
            {
                data.Remove(type);
            }
        }
              
        private void openSingleEntryView(LogEntry entry, int columnIndex, int arrayLength)
        {
            LogEntryView lv = new LogEntryView(entry, columnIndex, arrayLength);
            lv.Show();
        }

        private Image debug = (Image)Properties.Resources.ButtonDebugActive;
        private Image debug2 = (Image)Properties.Resources.ButtonDebugInactive;
        private Image error = (Image)Properties.Resources.ButtonErrorActive;
        private Image error2 = (Image)Properties.Resources.ButtonErrorInactive;
        private Image fatal = (Image)Properties.Resources.ButtonFatalActive;
        private Image fatal2 = (Image)Properties.Resources.ButtonFatalInactive;
        private Image info = (Image)Properties.Resources.ButtonInfoActive;
        private Image info2 = (Image)Properties.Resources.ButtonInfoInactive;
        private Image warn = (Image)Properties.Resources.ButtonWarnActive;
        private Image warn2 = (Image)Properties.Resources.ButtonWarnInactive;

        private void changeButtonStates()
        {
            if (sets.SelectedTypes != null)
            {
                if (sets.SelectedTypes.Contains(MessageTypes.INFO.ToString()))
                {
                    btnINFO.Image = info;
                    btnINFO.BorderStyle = BorderStyle.Fixed3D;
                }
                else
                {
                    btnINFO.Image = info2;
                    btnINFO.BorderStyle = BorderStyle.None;
                }
                if (sets.SelectedTypes.Contains(MessageTypes.DEBUG.ToString()))
                {
                    btnDEBUG.Image = debug;
                    btnDEBUG.BorderStyle = BorderStyle.Fixed3D;
                }
                else
                {
                    btnDEBUG.Image = debug2;
                    btnDEBUG.BorderStyle = BorderStyle.None;
                }
                if (sets.SelectedTypes.Contains(MessageTypes.WARN.ToString()))
                {
                    btnWARN.Image = warn;
                    btnWARN.BorderStyle = BorderStyle.Fixed3D;
                }
                else
                {
                    btnWARN.Image = warn2;
                    btnWARN.BorderStyle = BorderStyle.None;
                }
                if (sets.SelectedTypes.Contains(MessageTypes.ERROR.ToString()))
                {
                    btnERROR.Image = error;
                    btnERROR.BorderStyle = BorderStyle.Fixed3D;
                }
                else
                {
                    btnERROR.Image = error2;
                    btnERROR.BorderStyle = BorderStyle.None;
                }
                if (sets.SelectedTypes.Contains(MessageTypes.FATAL.ToString()))
                {
                    btnFATAL.Image = fatal;
                    btnFATAL.BorderStyle = BorderStyle.Fixed3D;
                }
                else
                {
                    btnFATAL.Image = fatal2;
                    btnFATAL.BorderStyle = BorderStyle.None;
                }
            }
        }
        
        /// <summary>
        ///     Opens the last file if "Open last file" is activated.
        /// </summary>
        private void setLastLoadedFileDialog()
        {
            ToolStripMenuItem historyMenu = (ToolStripMenuItem)menuStripMainWindow.Items["historyToolStripMenuItem"];
            if (sets.LastOpenFile && historyMenu.DropDownItems.Count > 0)
            {
                DialogResult result = MessageBox.Show("Load the last opened log file ?\n\"" + historyMenu.DropDownItems[0].Tag + "\"",
                        "Automatic Load", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
                if (result == DialogResult.Yes)
                {
                    toolStripHistoryItem_Click(historyMenu.DropDownItems[0], null);
                }
            }
        }

        /// <summary>
        ///     Checks what types are currently active and sets this
        ///     information in the statusbar.
        /// </summary>
        private void UpdateAllEntriesInfoStatusbar()
        {
            if (this.dataAccess == null || this.dataAccess.Indices == null || this.dataAccess.SortedIndices == null)
            {
                this.toolStripStatusLabelCurrent.Text = "";
                this.toolStripStatusLabelAll.Text = "";
                return;
            }
            StringBuilder separateTypes = new StringBuilder();
            bool firstType = true;
            foreach (MessageTypes type in MessageType.TypesArray())
            {
                if (type == MessageTypes.UNDEFINED)
                {
                    continue;
                }
                int countByType = 0;
                if (this.dataAccess.IndicesByMessageType.ContainsKey(type))
                {
                    countByType = this.dataAccess.IndicesByMessageType[type].Count;
                }
                separateTypes.Append((firstType ? "" : " | ") + type.ToString() + ": " + countByType);
                firstType = false;
            }
            //this.toolStripStatusLabelCurrent.Text = this.dataAccess.SortedIndices.Count.ToString();
            string sepTypes = separateTypes.Length > 0 ? "  (" + separateTypes.ToString() + ")" : "";
            this.toolStripStatusLabelAll.Text = this.dataAccess.SortedIndices.Count + sepTypes;
        }

        /// <summary>
        ///     Manages the dialog "Load log file".
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OpenFileDialog()
        {
            try
            {
                DialogResult result = openFileDialog.ShowDialog();
                if (result.Equals(DialogResult.OK))
                {
                    string filename = openFileDialog.FileName;
                    bool success = LoadLogfile(filename);

                    if (!success)
                    {
                        MessageBox.Show("Cannot open logfile !", "Loading Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                    }
                }
            }
            catch (Exception)
            {
                // Catch mysterious GDI+ exception
            }
            //this.listView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
        }

        private void checkForUpdateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Program.updater.Update(false);
        }

        private void revisionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Program.updater.Overview();
        }

        private void listView_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (e != null)
            {
                ColumnHeader header = this.listView.Columns[e.Column];
                if (header != null)
                {
                    Console.WriteLine("Selected to sort: " + header.Text);
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            LogFormatConfig config = new LogFormatConfig();
            config.Show();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ListView.ColumnHeaderCollection col = this.listView.Columns;
            StringBuilder builder = new StringBuilder("Columns:\n");
            foreach (ColumnHeader item in col)
            {
                builder.Append(" [" + item.Text + "] \t" + item.Width + "\n");
            }
            MessageBox.Show(builder.ToString());
        }

        private void MainWindow_Shown(object sender, EventArgs e)
        {
            this.formLoaded = true;
        }

        private void sendChangeRequestToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Program.updater.SendChangeRequest();
        }

        private void sendBugReportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Program.updater.SendBugReport();
        }

        private void btnFilter_Click(object sender, EventArgs e)
        {
            FilterCriteria crit = new FilterCriteria();
            if (dateTimePicker1.Enabled)
            {
                crit.DatetimeStart = dateTimePicker1.Value;
            }
            if (dateTimePicker2.Enabled)
            {
                crit.DatetimeStop = dateTimePicker2.Value;
            }
            if (textBoxFilter.Enabled && this.textBoxFilter.Text.Length > 0)
            {
                crit.FilterText = this.textBoxFilter.Text.ToLower();
            }
            btnResetFilter.Enabled = true;
            loadFileProgressBar.Show();
            backgroundWorkerFilter.RunWorkerAsync(new object[] { this.dataAccess, crit });
            
        }

        private long lastFileSize;

        private void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            if (e.ChangeType == WatcherChangeTypes.Changed && !backgroundFileIndexer.IsBusy)
            {
                FileInfo info = new FileInfo(e.FullPath);
                if (lastFileSize == info.Length)
                {
                    // Same event as before, skip
                    return;
                }
                lastFileSize = info.Length;
                Console.WriteLine("fileSystemWatcher_Changed: File changed, size is: " + info.Length.ToString());
                ProgressWindow progWin = new ProgressWindow(this.dataAccess);
                bool everythingOk = progWin.RunFileIndexer();
                if (!everythingOk)
                {
                    Console.WriteLine("fileSystemWatcher_Changed: File indexing failed.");
                }
                else
                {
                    RedrawListView();
                }
            }
        }

        private void backgroundWorkerFilter_DoWork(object sender, DoWorkEventArgs e)
        {
            object[] args = (object[]) e.Argument;
            DataAccess dataAccess = (DataAccess)args[0];
            FilterCriteria crit = (FilterCriteria)args[1];
            if (dataAccess == null)
            {
                MessageBox.Show("Load a file first.");
                return;
            }
            // Clear previously filtered list
            dataAccess.FilteredIndices = new List<IndexObject>();
            // Iterate all available indices
            int count = 1;
            List<IndexObject> indices = dataAccess.Indices;
            foreach (IndexObject item in indices)
            {
                // First Step: filter for selected type
                if (dataAccess.SelectedTypes.Contains(item.MessageType))
                {
                    if (crit != null)
                    {
                        // Second Step: filter by criteria
                        // Retrieve full log entry object for index
                        LogEntry entry = RetrieveNeededEntry(item);
                        if (entry == null)
                        {
                            Console.WriteLine(item.MessageType + " entry is null at index: " + item.FileIndex);
                            continue;
                        }
                        bool valid = true;
                        if (crit.DatetimeStart != null && !crit.DatetimeStart.Equals(new DateTime(0)))
                        {
                            valid &= entry.Datetime >= crit.DatetimeStart;
                        }
                        if (crit.DatetimeStop != null && !crit.DatetimeStop.Equals(new DateTime(0)))
                        {
                            valid &= entry.Datetime <= crit.DatetimeStop;
                        }
                        if (crit.FilterText != null)
                        {
                            string checkString = entry.Type + " " + entry.Package + " " + entry.Message;
                            valid &= checkString.ToLower().Contains(crit.FilterText);
                        }
                        // All conditions have been checked
                        if (valid)
                        {
                            dataAccess.FilteredIndices.Add(item);
                        }
                    }
                    else
                    {
                        dataAccess.FilteredIndices.Add(item);
                    }
                }
                backgroundWorkerFilter.ReportProgress(100 / (indices.Count / count++));
            }
            e.Result = dataAccess;
        }

        private void backgroundWorkerFilter_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            Console.WriteLine("Progress: " + e.ProgressPercentage);
            loadFileProgressBar.Value = e.ProgressPercentage;
        }

        private void backgroundWorkerFilter_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            loadFileProgressBar.Value = 100;
            loadFileProgressBar.Hide();
            DataAccess dataAccess = (DataAccess) e.Result;
            this.dataAccess = dataAccess;

            RedrawListView();
        }

        private void filterChkBxText_CheckedChanged(object sender, EventArgs e)
        {
            textBoxFilter.Enabled = filterChkBxText.Checked;
            enableFilterButton();
        }

        private void filterChkBxDateStart_CheckedChanged(object sender, EventArgs e)
        {
            dateTimePicker1.Enabled = filterChkBxDateStart.Checked;
            enableFilterButton();
        }

        private void filterChkBxDateEnd_CheckedChanged(object sender, EventArgs e)
        {
            dateTimePicker2.Enabled = filterChkBxDateEnd.Checked;
            enableFilterButton();
        }

        private void textBoxFilter_TextChanged(object sender, EventArgs e)
        {
            enableFilterButton();
        }

        private void enableFilterButton()
        {
            if ((filterChkBxText.Checked && textBoxFilter.Text.Length > 2) || filterChkBxDateStart.Checked || filterChkBxDateEnd.Checked)
            {
                btnFilter.Enabled = true;
            }
            else
            {
                btnFilter.Enabled = false;
            }
        }

        private void btnResetFilter_Click(object sender, EventArgs e)
        {
            this.dataAccess.FilteredIndices = null;
            RedrawListView();
        }

        private void chkBxWatchMode_CheckedChanged(object sender, EventArgs e)
        {
            fileSystemWatcher.EnableRaisingEvents = chkBxWatchMode.Checked;
        }
     }
}